package com.iwop.moto.controller;

import com.alibaba.druid.wall.violation.ErrorCode;
import com.alibaba.fastjson.JSON;
import com.iwop.moto.comm.Comm;
import com.iwop.moto.comm.ErrCode;
import com.iwop.moto.model.*;
import com.iwop.moto.service.*;
import com.iwop.moto.utils.PushNoticeUtil;
import com.iwop.moto.utils.UnionPay.CryptoUtil;
import com.iwop.moto.utils.UnionPay.UnionPayUtil;
import com.iwop.moto.utils.http.SessionUtils;
import com.iwop.moto.utils.stringUtil.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @功能:  银联支付
 */
@Controller
public class UnionPayController extends BaseController {

    @Autowired
    private UserService userService;

    @Autowired
    private MPaymentService mPaymentService;

    @Autowired
    FOrderServiceService fOrderServiceService;

    @Autowired
    MCouponService mCouponService;

    @Autowired
    private StoreService storeService;

    @Autowired
    MGPOrderService mgpOrderService;

    @Autowired
    MOrderPurchaseService mOrderPurchaseService;

    @Autowired
    MBrokerageService mBrokerageService;

    @Autowired
    PromotionService promotionService;
    /**
     * @功能: 银联H5支付
     * @参数: userId 付款方用户ID (必填)
     * @参数: sellerUserId 收款方用户ID(选填)
     * @参数: money 金额 (必填)
     * @参数: outTradeNo 订单号(选填)
     * @参数: cuponId 优惠券(选填)
     * @参数: brokerage 佣金(选填)
     * @参数: body  商品描述(选填)
     * @参数: payAcctNo  银行卡(选填)
     * @参数: payType 交易类型[Service:服务订单支付][Goods:商品订单支付][Topup:充值][Backspace：回退][TRANSFER：转账][Balance:余额支付](必填)
     */
    @RequestMapping(value="/api/union/h5/pay")
    public ModelAndView ApiUnionH5Pay(){
        ModelAndView mv = new ModelAndView();
        SuperRecordModel srm = this.getSRModel();
        if(srm.get("userId")==null || srm.get("body")==null || srm.get("money")==null ||
                srm.get("payType")==null){
            return errorMv(ErrCode.ERROR_PARAMETER);
        }
        double money = Double.parseDouble(srm.getString("money"));
        //判断优惠券
        String couponId = srm.getString("couponId");
        String userId = srm.getString("userId");
        String outTradeNo = srm.getString("outTradeNo");
        double couponMoney=0;
        if(srm.containsKey("couponId")&& (!StringUtils.isEmpty(couponId))){
            SuperRecordModel superRecordModel=new SuperRecordModel();
            superRecordModel.put("user_id", userId);
            superRecordModel.put("coupon_id",srm.getString("couponId"));
            superRecordModel.put("payMoney",Double.parseDouble(srm.getString("money")));
            SuperRecordModel sp = mCouponService.getUserCouponByCouponIdAndUserId(superRecordModel);
            if(sp==null ||sp.size()==0){
                return errorMv(ErrCode.ERROR_COUPON_MONEY);
            }
            couponMoney=((BigDecimal)sp.get("money")).doubleValue();
        }

        //判断佣金
        double brokerages=0;
        String brokerage = srm.getString("brokerage");
        if(!StringUtils.isEmpty(brokerage)){
            brokerages=Double.parseDouble(brokerage);
            User user = userService.getUserBySid(userId);
            double redPacket = user.getRedPacket();
            if(redPacket<brokerages){
                return errorMv(ErrCode.BROKERAGE_ERROR);
            }
        }


        String payTradeNo="";
        double payMoney=0;//订单金额
        String content="";

        //判断订单
        if(outTradeNo.contains("Ho")){
            MGPOrder oneBySid = mgpOrderService.findOneBySid(outTradeNo);
            if(oneBySid==null){
                return errorMv(ErrCode.EXSIT_ORDER_INFO);
            }
            if(oneBySid.getStatusFlag().equals("1")){
                return errorMv(ErrCode.ERROR_ORDER_SERVICE_SUBMIT);
            }
            payMoney = oneBySid.getMoney();
            payTradeNo=SequenceUtil.Serial("Ho");
            oneBySid.setPayTradeNo(payTradeNo);
            content=oneBySid.getContent();
            mgpOrderService.updateMGPOrder(oneBySid);
        }else if(outTradeNo.contains("Co")){
            MOrderPurchase oneById = mOrderPurchaseService.findOneById(outTradeNo);
            if(oneById==null){
                return errorMv(ErrCode.EXSIT_ORDER_INFO);
            }
            if(oneById.getStatus()==1){
                return errorMv(ErrCode.ERROR_ORDER_SERVICE_SUBMIT);
            }
            payMoney=oneById.getMoney();
            payTradeNo=SequenceUtil.Serial("Co");
            oneById.setPayOrderNo(payTradeNo);
            mOrderPurchaseService.updateOrderPurchase(oneById);
        }else if(outTradeNo.contains("SO")){
            SuperRecordModel superRecordModel = fOrderServiceService.getStoreOrderByOrderNo(outTradeNo);
            if(superRecordModel==null){
                return errorMv(ErrCode.EXSIT_ORDER_INFO);
            }
            if(superRecordModel.getString("pushstatus").equals("1")){
                return errorMv(ErrCode.ERROR_ORDER_SERVICE_SUBMIT);
            }
            payMoney=((BigDecimal)superRecordModel.get("money")).doubleValue();
            payTradeNo= SequenceUtil.Serial("So");
            superRecordModel.put("pay_order_no", payTradeNo);
            fOrderServiceService.updateStoreOrder(superRecordModel);
        }else {
            if(!srm.getString("payType").equals("Topup")){
                return errorMv(ErrCode.ERROR_SYSTEM);
            }
        }

        //验证金额
        double subtract = BigDecimalUtil.getSubtract(payMoney, couponMoney);//减去优惠券金额
        double pay_money = BigDecimalUtil.getSubtract(subtract, brokerages);//减去佣金,获取到支付金额

        if(pay_money<0){
            return errorMv(ErrCode.BANK_ERROR_MONEY_FORMAT);
        }

        if(pay_money==0){
            pay_money=0.01;
        }

        if(srm.getString("payType").equals("Topup")){
            payTradeNo=SequenceUtil.Serial("SEQ-");
            outTradeNo=payTradeNo;
            pay_money=money;
        }

        if(pay_money!=money){
            return errorMv(ErrCode.ORDER_MONEY_ERROR);
        }
        Map<String, String> map = new HashMap<>();
        map.put("oid_partner",Comm.UnpayPartner);
        map.put("user_id",srm.getString("userId"));
        map.put("no_order",payTradeNo );
        Date date = new Date();
        map.put("dt_order", DateFormatter.simpleDateTimeUnionFormat(date));
        map.put("name_goods", srm.getString("body"));
        map.put("money_order", pay_money+"");
        map.put("notify_url", Comm.HTTP_URL+"/api/union/pay/callback");
        map.put("url_return", Comm.HTTP_URL+"/query/union/info");//H5页面点击返回需回到的页面，先默认首页
        try {
            if(srm.get("payAcctNo")!=null && srm.getString("payAcctNo").trim().equals("")) {
                map.put("pay_acct_no",UnionPayUtil.RsaPublicKeyEncrypt(srm.getString("payAcctNo")));
            }
            map.put("sign",UnionPayUtil.genSign(map));

            MPayment mPayment = mPaymentService.findPaymentByOutTradeNo(outTradeNo);

            boolean bUpdate = true; //更新标示
            if(mPayment==null ){//0状态未 交易前生成的数据
                bUpdate = false;//新增标示
                mPayment = new MPayment();
                mPayment.setPayId(ObjectId.UUID());
            } else if(mPayment.getPayStatus()!=null && !mPayment.getPayStatus().equals("0")){//订单号已经支付成功
                return errorMv("重复订单支付");
            }
            mPayment.setMchType("UNIONPAY");//银联交易
            mPayment.setPayType(srm.getString("payType"));
            mPayment.setBuyerUserId(userId);//开摩邦用户id(买家/付款方)
            if(mPayment.getPayType().equals("Topup")) {//如果是充值
                mPayment.setSellerUserId(mPayment.getBuyerUserId());//买家和卖家ID一致,开摩邦用户id(卖家/收款方)
            }else {
                mPayment.setSellerUserId(srm.getString("sellerUserId"));
            }
            Double bro=BigDecimalUtil.getMultiply(payMoney,Comm.BROKERAGE);
            mPayment.setPayFee(bro);
            mPayment.setContent(content);
            mPayment.setPayMoney(BigDecimalUtil.getSubtract(payMoney,bro));//交易金额
            mPayment.setPayActualMoney(pay_money);
            mPayment.setOutTradeNo(outTradeNo);
            mPayment.setCouponId(couponId);
            mPayment.setBrokerage(brokerages);
            mPayment.setMchId(Comm.UnpayPartner);
            mPayment.setPayStatus("0");//交易前状态.交易后
            mPayment.setPayDescribe(map.get("name_goods") == null ? null : map.get("name_goods").toString());
            mPayment.setAddTime(date);
            if(bUpdate){
                mPaymentService.update(mPayment);
            }else {
                mPaymentService.insert(mPayment);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return errorMv(ErrCode.ERROR_SYSTEM);
        }
        mv.addObject("unpay",map);
        mv.addObject("unionPayPostUrl",Comm.UnpayHttpUrl+"/payServlet");
        mv.setViewName("union/unionpay");
        return mv;
    }

    /**
     * 退款接口
     * */
    @RequestMapping(value = "/api/union/pay/reback")
    @ResponseBody
    public ModelAndView ApiUnionPayReback(HttpServletRequest request){
        ModelAndView mv = new ModelAndView();
        String oid = request.getParameter("oid");

        MPayment mPayment= new MPayment();
        String payTradeNo ="";
        String ori_no_order ="";
        double payMoney = 0;//订单金额

         if(!oid.contains("SEQ-")){
            mPayment.setOutTradeNo(oid);
            judgeOrderType(oid,mPayment);
        }else {
            mPayment.setOutTradeNo(oid);
        }

        //判断订单 查询付款订单
        if(oid.contains("Ho")){
            MGPOrder oneBySid = mgpOrderService.findOneBySid(oid);
            if(oneBySid==null){
                return errorMv(ErrCode.EXSIT_ORDER_INFO);
            }
            payTradeNo = SequenceUtil.Serial("Ho");
            ori_no_order = oneBySid.getPayTradeNo();
        }else if(oid.contains("Co")){
            MOrderPurchase oneById = mOrderPurchaseService.findOneById(oid);
            if(oneById==null){
                return errorMv(ErrCode.EXSIT_ORDER_INFO);
            }
            payTradeNo = SequenceUtil.Serial("Co");
            ori_no_order = oneById.getPayOrderNo();

        }else if(oid.contains("SO")){
            SuperRecordModel superRecordModel = fOrderServiceService.getStoreOrderByOrderNo(oid);
            if(superRecordModel==null){
                return errorMv(ErrCode.EXSIT_ORDER_INFO);
            }
            payTradeNo= SequenceUtil.Serial("So");
            ori_no_order = superRecordModel.getString("pay_order_no");
        }else {


        }

        //根据订单号码查询

        MPayment paymentByOutTradeNo = mPaymentService.findPaymentByOutTradeNo(mPayment.getOutTradeNo());
        if(paymentByOutTradeNo==null){
            return errorMv(ErrCode.ERROR_SYSTEM);
        }
        Map<String, String> map = new HashMap<>();
        map.put("oid_partner",Comm.UnpayPartner);
        map.put("no_order",payTradeNo);
        map.put("ori_no_order",ori_no_order);
        map.put("dt_order", DateFormatter.simpleDateTimeUnionFormat(paymentByOutTradeNo.getPayTime()));
        map.put("money_order", paymentByOutTradeNo.getPayActualMoney()+"");
        map.put("notify_url", Comm.HTTP_URL+"/api/union/pay/reback/callback");

        try {
            map.put("sign",UnionPayUtil.genSign(map));
        } catch (Exception e) {
            e.printStackTrace();
        }

        mv.addObject("reback",map);
        mv.addObject("rebackPostUrl",Comm.UnpayHttpUrl+"/tkServlet");
        mv.setViewName("union/reback");
        return mv;
    }


    /**
     * 退款回调
     * */
    @RequestMapping(value = "/api/union/pay/reback/callback")
    @ResponseBody
    public String ApiUnionPayReCallback(HttpServletRequest request) throws Exception {
        Map returnMap = new HashMap<>();
        Map<String,String []> reqParamMap = request.getParameterMap();
        Map result = new HashMap<>();
        for (String key : reqParamMap.keySet()) {
            String [] values = reqParamMap.get(key);
            if (values !=null && !"".equals(values)) {
                result.put(key,values[0]);
            }
        }
        String sign = result.get("sign").toString();//原民生返回签名
        String params = UnionPayUtil.beanToUrlParams(result);
        boolean verifySign = UnionPayUtil.verifySign(params,sign);
        String no_order = result.get("no_order").toString();
        if(verifySign) {//签名成功
            MPayment mPayment = mPaymentService.findPaymentByOutTradeNo(no_order);
            if(no_order.equals("Ho")){
                MGPOrder gpOrderByPayOutTradeNo = mgpOrderService.findGPOrderByPayOutTradeNo(no_order);
                gpOrderByPayOutTradeNo.setStatusFlag("0");
                mgpOrderService.updateMGPOrder(gpOrderByPayOutTradeNo);
            }else if(no_order.equals("Co")){
                MOrderPurchase oneByoutTradeNo = mOrderPurchaseService.findOneByoutTradeNo(no_order);
                oneByoutTradeNo.setStatus(0);
                mOrderPurchaseService.updateOrderPurchase(oneByoutTradeNo);
            }else if(no_order.equals("So")){
                SuperRecordModel model = fOrderServiceService.getStoreOrderByPayOrderNo(no_order);
                model.put("status_flag","0");
            }else {
                mPayment.setPayStatus("0");
                mPaymentService.update(mPayment);
            }
            if(!mPayment.getPayType().equals("Topup")){
                User user = userService.getUserBySid(mPayment.getSellerUserId());
                Double rmoney = user.getRmoney();
                double subtract = BigDecimalUtil.getSubtract(rmoney, mPayment.getPayMoney());
                user.setRmoney(subtract);
                MBrokerage mBrokerage=mBrokerageService.findBrokerageByOutTradeNo(mPayment.getOutTradeNo());
                if(mBrokerage!=null){
                    double payMoney = mBrokerage.getPayMoney();
                    user.setRedPacket(BigDecimalUtil.getSubtract(user.getRedPacket(),payMoney));
                    user.setNewUser("new");
                    String keyName=mPayment.getBuyerUserId() +"_new";
                    SessionUtils.setKeyValue(keyName, "new");
                }
                userService.updateRedPacketBySid(user);
                if(!StringUtils.isEmpty(mPayment.getCouponId())){
                    updateConpon(mPayment, "1");
                }
            }
            return JsonUtils.toJsonString(respMsgToBank());

        }else {
            ErrorLog(null, "/api/union/pay/reback/callback:银联回调签名验证失败",JsonUtils.toJsonString(result));
        }

        return JsonUtils.toJsonString(respMsgToBank());
    }

    /**
     * @功能: 银联支付回调函数
     */
    @RequestMapping(value = "/api/union/pay/callback")
    @ResponseBody
    public String ApiUnionPayCallback(@ModelAttribute UnionPayBackInfo unionPayBackInfo){

        Map<String, String> result = UnionPayUtil.beanToMap(unionPayBackInfo);
        try{
            System.out.println("银联支付回调参数:\r\n"+JsonUtils.toJsonString(unionPayBackInfo));
            String sign = unionPayBackInfo.getSign();//原民生返回签名
            String params = UnionPayUtil.beanToUrlParams(result);
            boolean verifySign = UnionPayUtil.verifySign(params,sign);
            String no_order = unionPayBackInfo.getNo_order();
            if(verifySign){ //签名成功
                if(unionPayBackInfo.getResp_code().equals("00")){// 00 代表成功
                    MPayment mPayment =new MPayment();
                    if(no_order.contains("SEQ-")){
                        mPayment = mPaymentService.findPaymentByOutTradeNo(no_order);
                        if(mPayment.getPayStatus().equals("1")){
                            ErrorLog(null,"/api/union/pay/callback:重复回调",JsonUtils.toJsonString(unionPayBackInfo));
                            return JsonUtils.toJsonString(respMsgToBank());
                        }
                        mPayment.setPayTradeNo(unionPayBackInfo.getOid_paybill());
                        User user = userService.getUserBySid(mPayment.getSellerUserId());
                        mPayment.setOriginalTmoney(user.getRmoney());
                        Double money_order = Double.valueOf(unionPayBackInfo.getMoney_order());
                        user.setRmoney(user.getRmoney()+money_order);//用户操作成功后金额
                        mPayment.setModifyTmoney(user.getRmoney());
                        userService.updateUserRmoneyBySid(user);
                        mPayment.setPayTime(new Date());
                        mPayment.setPayStatus("1");//标识为交易成功
                        mPaymentService.update(mPayment);
                    } else{
                        String updateOrder = judgeOrderType(no_order, mPayment);
                        if(StringUtils.isEmpty(updateOrder)){
                            ErrorLog(null,"/api/union/pay/callback:订单已经支付",JsonUtils.toJsonString(unionPayBackInfo));
                            return JsonUtils.toJsonString(respMsgToBank());
                        }
                        mPayment = mPaymentService.findPaymentByOutTradeNo(mPayment.getOutTradeNo());

                        if(mPayment.getBrokerage()==null){
                            mPayment.setBrokerage(0.00);
                        }
                        //推广佣金
                        addBrokerage(mPayment.getBuyerUserId(),BigDecimalUtil.getAdd(mPayment.getPayMoney(),mPayment.getBrokerage()),mPayment.getOutTradeNo());

                        //更新用户钱包
                        User user = userService.getUserBySid(mPayment.getSellerUserId());
                        mPayment.setOriginalTmoney(user.getRmoney());

                        double modifyMoney = BigDecimalUtil.getAdd(user.getRmoney(), mPayment.getPayMoney());
                        user.setRmoney(modifyMoney);
                        mPayment.setModifyTmoney(modifyMoney);
                        userService.updateUserRmoneyBySid(user);
                        //更新用户优惠券
                        updateConpon(mPayment,"2");
                        if(mPayment.getPayTradeNo().isEmpty())
                        {
                            mPayment.setPayTradeNo(unionPayBackInfo.getOid_paybill());
                        }
                        mPayment.setPayTime(new Date());
                        mPayment.setPayStatus("1");//标识为交易成功
                        mPaymentService.update(mPayment);
                        //PushNoticeUtil.sendPersonNotice("您有一笔订单已付款成功!", "store", storeUser.getSid());
                    }
                } else {
                    ErrorLog(null, "/api/union/pay/callback:银联应答失败", JsonUtils.toJsonString(unionPayBackInfo));
                }

            } else {
                ErrorLog(null, "/api/union/pay/callback:银联回调签名验证失败",JsonUtils.toJsonString(unionPayBackInfo));
            }
        } catch (Exception e){
            ErrorLog(e,"/api/union/pay/callback:银联回调异常",JsonUtils.toJsonString(unionPayBackInfo));
        }
        return JsonUtils.toJsonString(respMsgToBank());
    }

    @RequestMapping(value = "/query/union/info")
    @ResponseBody
    public ResultModel queryUnionInfo(HttpServletRequest request,@ModelAttribute UnionPayBackInfo unionPayBackInfo) throws Exception {
            UnionPayUtil.getUnionPayInfo(unionPayBackInfo.getNo_order(),unionPayBackInfo.getOid_paybill(),unionPayBackInfo.getDt_order());
        return getSucceed(ErrCode.SUCCEED);

    }

    private void updateConpon(MPayment mPayment,String status){
        if(!StringUtils.isEmpty(mPayment.getCouponId())){
            SuperRecordModel superRecordModel=new SuperRecordModel();
            superRecordModel.put("coupon_id",mPayment.getCouponId());
            superRecordModel.put("user_id",mPayment.getBuyerUserId());
            SuperRecordModel srm = mCouponService.getUserCouponByCouponIdAndUserId(superRecordModel);
            srm.put("status_flag",status);
            srm.put("status_time",new Date());
            mCouponService.updateUserCouponStatusBySid(srm);
        }
    }

    private String judgeOrderType(String out_trade_no, MPayment mPayment){
        if(out_trade_no.contains("Ho")){
            MGPOrder mgpOrder = mgpOrderService.findGPOrderByPayOutTradeNo(out_trade_no);
            if(mgpOrder.getStatusFlag().equals("1")){
                return null;
            }
            mPayment.setOutTradeNo(mgpOrder.getOrderNo());
            mgpOrder.setStatusFlag("1");
            mPayment.setContent(mgpOrder.getContent());
            mgpOrderService.updateMGPOrder(mgpOrder);
        }else if(out_trade_no.contains("Co")){
            MOrderPurchase mOrderPurchase = mOrderPurchaseService.findOneByPayOrderNo(out_trade_no);
            if(mOrderPurchase.getStatus()==1){
                return null;
            }
            mOrderPurchase.setStatus(1);
            mOrderPurchase.setPrize(1);
            mPayment.setOutTradeNo(mOrderPurchase.getSid());
            mOrderPurchaseService.updateOrderPurchase(mOrderPurchase);
        }else {
            SuperRecordModel service = fOrderServiceService.getStoreOrderByPayOrderNo(out_trade_no);
            if(service.getString("pushstatus").equals("1")){
                return null;
            }
            mPayment.setOutTradeNo(service.getString("orderno"));
            service.put("pushstatus", "1");//支付成功
            fOrderServiceService.updateStoreOrderStatus(service);
        }
        return "success";
    }

    /**
     *添加佣金
     * */
    public void addBrokerage(String user_id, double moneys, String outTradeNo){
        if(moneys>5){
            String keyName=user_id +"_new";
            String valueFromSession = (String) SessionUtils.getValueFromSession(keyName);
            if(!StringUtils.isEmpty(valueFromSession)){
                if(valueFromSession.equals("new")){
                    String hostUserInfo = promotionService.findHostUserById(user_id);
                    int count=promotionService.countFromUserByHostId(hostUserInfo);
                    double money=getBrokerage(count);
                    if(!StringUtils.isEmpty(hostUserInfo)){
                        User userBySid = userService.getUserBySid(hostUserInfo);
                        if(userBySid!=null){
                            MBrokerage mBrokerage=new MBrokerage();
                            mBrokerage.setSid(ObjectId.UUID());
                            mBrokerage.setSellerUserId(userBySid.getSid());
                            mBrokerage.setBuyerUserId(user_id);
                            mBrokerage.setOriginalTmoney(userBySid.getRedPacket());
                            double modifyTmoney = userBySid.getRedPacket() + money;
                            mBrokerage.setModifyTmoney(modifyTmoney);
                            mBrokerage.setPayMoney(money);
                            mBrokerage.setPayStatus("1");
                            mBrokerage.setPayType("WXPAY");
                            mBrokerage.setPayTime(new Date());
                            mBrokerage.setOutTradeNo(outTradeNo);
                            mBrokerageService.insert(mBrokerage);
                            userBySid.setRedPacket(modifyTmoney);
                            userBySid.setNewUser("old");
                            userService.updateRedPacketBySid(userBySid);
                            SessionUtils.setKeyValue(keyName,"old");
                            User userBySid1 = userService.getUserBySid(user_id);
                            userBySid1.setNewUser("old");
                            userService.updateRedPacketBySid(userBySid1);
                        }
                    }
                }
            }
        }
    }

    private double getBrokerage(int people){
        if(people<19){
            return 4;
        }else if (people<99){
            return 5;
        }else {
            return 6;
        }
    }

    /**
     *
     *  返回响应通知银联
     *
     */

    private Map respMsgToBank(){
        Map respMap = new HashMap<>();
        respMap.put("resp_code","00");
        respMap.put("resp_msg","交易成功");
        try {
            respMap.put("sign",UnionPayUtil.genSign(respMap));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return respMap;
    }

}
